package com.gitee.target123.develop.mysql.aop;

import com.gitee.target123.develop.mysql.annotation.InsertRedisLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

@Aspect
public class InsertRedisLockAop {

    private RedisTemplate<String,String> redisTemplate;

    public InsertRedisLockAop(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Pointcut("@annotation(com.gitee.target123.develop.mysql.annotation.InsertRedisLock)")
    public void methodPointcut(){
    }

    @Around(value = "methodPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        Method[] methods = signature.getDeclaringType().getDeclaredMethods();

        Method targetMethod = Stream.of(methods)
                .filter(m -> m.getName().equals(methodName))
                .filter(m -> m.getParameterCount() == args.length)
                .findFirst()
                .orElse(null);
        if (targetMethod!=null){
            InsertRedisLock redisLock = targetMethod.getAnnotation(InsertRedisLock.class);
            if (redisLock!=null){
                String keyPrefix = redisLock.keyPrefix();
                String keyProperty = redisLock.keyProperty();
                String redisKey;
                try {
                    Field field = args[0].getClass().getDeclaredField(keyProperty);
                    field.setAccessible(true);
                    Object value = field.get(args[0]);
                    redisKey = value!=null ? keyPrefix + value : null;
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    redisKey = null;
                }

                if (redisKey!=null){
                    Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(redisKey, "1", 5, TimeUnit.SECONDS);
                    if (aBoolean != null && aBoolean){
                        return joinPoint.proceed();
                    }
                }
            }
        }
        return 0;
    }

}
